/*******************************************************************************
 * Copyright (C), 2014, BeeIoT Tech. Co., Ltd. 
 * FileName:      option.c
 * Author:        lvxin 
 * Version :      1.0
 * Date:          2014-07-31 10:36:22
 * Description:   系统配置相关功能
 * Function List: // 主要函数及其功能
 * 1. ------- 
 * History:
 * <author>   <time>                <version >  <desc> 
 * lvxin      2014-07-31 10:36:22   1.0         build this moudle 
 ******************************************************************************/

/*******************************************************************************
 *  *INCLUDES
 *  */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "option.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
//#include "iap.h"


#define     LINUX 0
#define     LPC1114 1

#define     PLATFORM  LINUX
//#define     PLATFORM  LPC1114
/*******************************************************************************
 *  *MICROS
 *  */
#define DisableIRQ() __disable_irq()
#define EnableIRQ()  __enable_irq()

/*******************************************************************************
 *  *CONSTANTS
 *  */
#define         OPTION_CRC_16_POLYNOMIALS      0x8005    

/*******************************************************************************
 *  *LOCAL FUNCTIONS
 *  */

/*需要按照需求修改这两个函数，调用外部的读写FLASH的接口*/
static int _read (void *args, void *buffer, int len);
static int _write (void *args, const void *data, int len);

static uint16_t CRC16(uint8_t *data, int len);//计算数据的CRC16值

/*******************************************************************************
 * Function:      _read()
 * Description:   从物理介质读取数据
 * Calls:         _write()   --存储到物理介质
 * Called By:     None
 * Input:         args  --附加参数
 *                data  --数据
 *                len   --数据长度
 * Return:        0 --存储成功
 *                -1 --存储失败
 * Others:        None
 ******************************************************************************/
static int _read (void *args, void *data, int len)
#if   (PLATFORM == LPC1114)
{
  int i;
	for (i=0; i<len; i++)
	{
		*((uint8_t*)data + i) = *((uint8_t *)str_data + i);
}
 // memcpy (data,str_data,len);
  return 0;
}
#endif
#if   (PLATFORM == LINUX)
{
 int rc;
 int fd = open ("setup", O_RDWR|O_CREAT, 0666);
 if (fd == -1)
 {
   perror("Open file");
   return -1;
 }

 rc = read (fd, data, len);
 if (rc == -1)
 {
   perror("Open file");
   return -1;
 }

 close (fd);
  return 0;

}
#endif

/*******************************************************************************
 * Function:      _write()
 * Description:   写入到物理介质
 * Calls:         None
 * Called By:     None
 * Input:         args  --附加参数
 *                data  --数据
 *                len   --数据长度
 * Return:        0 --存储成功
 * Others:        None
 ******************************************************************************/
static int _write (void *args, const void *data, int len)
#if   (PLATFORM == LPC1114)
{
	int ucErr;
	IAP_Entry = (void(*)())IAP_ENTER_ADR;                           //³õÊ¼»¯º¯ÊýÖ¸ÕëIAP_Entry 
	DisableIRQ();  													//ÔÚIAP²Ù×÷Ö®Ç°±ØÐë¹Ø±ÕËùÓÐÖÐ¶Ï
	ucErr = sectorPrepare(13,13);                                     //×¼±¸ÉÈÇø7                  
	ucErr = sectorErase(13,13);                                       //²Á³ýÉÈÇø7                  
	ucErr = blankChk(13,13) ;                                         //²é¿ÕÉÈÇø7                   
	ucErr = sectorPrepare(13,13);                                     //Ñ¡ÔñÉÈÇø7                  
	ucErr = ramCopy(0x0000D000, (uint32_t)data, 1024);        //Ð´Êý¾Ýµ½ÉÈÇø7               
	ucErr = dataCompare(0x0000D000, (uint32_t)data, 1024);    //±È½ÏÊý¾Ý
	if(ucErr){};														//Êý¾ÝÃ»ÓÐÕýÈ·Ð´µ½FLASHÖÐ
	EnableIRQ();													//´æ´¢Êý¾ÝÍê³É¿ªÆôÖÐ¶Ï

	return 0;
}
#endif
#if   (PLATFORM == LINUX)
{
 int rc;
 int fd = open ("setup", O_RDWR|O_CREAT, 0666);
 if (fd == -1)
 {
   perror("Open file");
   return -1;
 }

 rc = write (fd, data, len);
 if (rc == -1)
 {
   perror("Open file");
   return -1;
 }
 close (fd);
	return 0;
}
#endif

/*******************************************************************************
 * Function:      CRC16()
 * Description:   对数据进行简易的CRC16校验
 * Calls:         None
 * Called By:      
 * Input:         data
 * Return:        crc校验值
 * Others:        None
 ******************************************************************************/
static uint16_t CRC16(uint8_t *data, int len)
{
  uint16_t i, tmp;
  uint16_t CRC = 0xFFFF;

  while (len--)
  {
    tmp = *((uint8_t *)data ++);
    CRC ^= (((uint16_t) tmp) << 8);
    for (i = 0; i < 8; i++)
    {
      if (CRC & 0x8000)
        CRC = (CRC << 1) ^ OPTION_CRC_16_POLYNOMIALS;
      else
        CRC <<= 1;
    }
  }
  return CRC;
}

/*******************************************************************************
 *  *PUBLIC FUNCTIONS
 *  */

/*******************************************************************************
 * Function:      option_set()
 * Description:   保存系统设置
 * Calls:         _write()   --存储到物理介质
 * Called By:     None
 * Input:         option --用来存储系统设置的地址
 * Return:        0 --存储成功
 *                1 --存储数据异常
 * Others:        None
 ******************************************************************************/
int option_set (option_t *option)    //保存设置
{
  int rc;

  uint16_t tmp_crc;

  option->_crc = 0;
  tmp_crc = option->_crc = CRC16 ((uint8_t *)option, sizeof(option_t));
  rc = _write (NULL, option, sizeof (option_t));
  //option_get (option);
  if (option->_crc != tmp_crc)
  {
    return 1;
  }
  return rc;
}

/*******************************************************************************
 * Function:      option_get()
 * Description:   读取系统设置
 * Calls:         _read()
 * Called By:     None
 * Input:         option --用来存储系统设置的地址
 * Return:        1 --数据初次存储，并成功格式化
 *                2 --CRC校验错误
 *               0 1 2
 * Others:        None
 ******************************************************************************/
int option_get (option_t *option)
{
  int rc = 0;
  int i;
  uint16_t tmpcrc;
  uint16_t crc;

  rc = _read (NULL, option, sizeof (option_t));

  tmpcrc = option->_crc;
  option->_crc = 0;
  crc = CRC16 ((uint8_t *)option, sizeof(option_t));
  if (option->_flag != 0xA5){ //Flash未存储过数据
    /*数据结构清零*/
    for (i = 0; i < sizeof (option_t); i ++)
    {
      *((uint8_t *)option + i)= 0;
    }

#if   (PLATFORM == LPC1114)
	//0根，1设置，2大棚数量，3温度阈值，4湿度阈值，5报警电话，6报警时间，7传感器校准，8设备绑定，9通信测试
	//78温度校准，79湿度校准
	GreenHouse.number = 5;									//大棚数量初始化
	GreenHouse.id_menu_cnt[0] = 1;                          //菜单数量初始化
	GreenHouse.id_menu_cnt[1] = 8;
	GreenHouse.id_menu_cnt[2] = 1;
	GreenHouse.id_menu_cnt[5] = 4;
	GreenHouse.id_menu_cnt[7] = 2;
	GreenHouse.id_menu_cnt[9] = 1;
	GreenHouse.id_menu_cnt[3] = GreenHouse.number + 1;
	GreenHouse.id_menu_cnt[4] = GreenHouse.number + 1;
	GreenHouse.id_menu_cnt[6] = GreenHouse.number + 1;
	GreenHouse.id_menu_cnt[8] = GreenHouse.number;
	GreenHouse.id_menu_cnt[78] = GreenHouse.number;
	GreenHouse.id_menu_cnt[79] = GreenHouse.number;
	MY_ID();                                                //设备ID初始化
	for(i = 1; i < 21; i++)                                 //报警开关标识初始化
	{
		GreenHouse.dp[i].temperature_switch = 0;
		GreenHouse.dp[i].humidity_switch = 0;
	}
					
#endif
    option->_flag = 0xA5; //设置标识
    option->_crc = CRC16 ((uint8_t*)option, sizeof(option_t));
    option_set (option);
    option_get (option);
    return 1;
  }

  if (crc != tmpcrc) //数据异常
  {
    option->_crc = tmpcrc;
    return 2;
  }

  option->_crc = tmpcrc;
  return rc;
}

